package cn.com.anypay.manager.common.validation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * 密码强度验证器实现
 */
public class PasswordStrengthValidator implements ConstraintValidator<PasswordStrength, String> {

    private int minLength;
    private int maxLength;
    private boolean requireUppercase;
    private boolean requireLowercase;
    private boolean requireDigit;
    private boolean requireSpecialChar;
    private String allowedSpecialChars;
    private boolean forbidCommonPasswords;
    private boolean forbidSequentialChars;
    private int maxRepeatingChars;

    // 常见弱密码列表
    private static final Set<String> COMMON_PASSWORDS = Set.of(
        "password", "123456", "123456789", "qwerty", "abc123", 
        "password123", "admin", "letmein", "welcome", "monkey",
        "1234567890", "qwertyuiop", "asdfghjkl", "zxcvbnm"
    );

    @Override
    public void initialize(PasswordStrength constraintAnnotation) {
        this.minLength = constraintAnnotation.minLength();
        this.maxLength = constraintAnnotation.maxLength();
        this.requireUppercase = constraintAnnotation.requireUppercase();
        this.requireLowercase = constraintAnnotation.requireLowercase();
        this.requireDigit = constraintAnnotation.requireDigit();
        this.requireSpecialChar = constraintAnnotation.requireSpecialChar();
        this.allowedSpecialChars = constraintAnnotation.allowedSpecialChars();
        this.forbidCommonPasswords = constraintAnnotation.forbidCommonPasswords();
        this.forbidSequentialChars = constraintAnnotation.forbidSequentialChars();
        this.maxRepeatingChars = constraintAnnotation.maxRepeatingChars();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        if (value == null) {
            return false;
        }

        // 长度检查
        if (value.length() < minLength || value.length() > maxLength) {
            return false;
        }

        // 字符类型检查
        if (requireUppercase && !containsUppercase(value)) {
            return false;
        }

        if (requireLowercase && !containsLowercase(value)) {
            return false;
        }

        if (requireDigit && !containsDigit(value)) {
            return false;
        }

        if (requireSpecialChar && !containsSpecialChar(value)) {
            return false;
        }

        // 常见弱密码检查
        if (forbidCommonPasswords && isCommonPassword(value)) {
            return false;
        }

        // 连续字符检查
        if (forbidSequentialChars && hasSequentialChars(value)) {
            return false;
        }

        // 重复字符检查
        if (hasExcessiveRepeatingChars(value)) {
            return false;
        }

        return true;
    }

    /**
     * 检查是否包含大写字母
     */
    private boolean containsUppercase(String password) {
        return Pattern.compile("[A-Z]").matcher(password).find();
    }

    /**
     * 检查是否包含小写字母
     */
    private boolean containsLowercase(String password) {
        return Pattern.compile("[a-z]").matcher(password).find();
    }

    /**
     * 检查是否包含数字
     */
    private boolean containsDigit(String password) {
        return Pattern.compile("[0-9]").matcher(password).find();
    }

    /**
     * 检查是否包含特殊字符
     */
    private boolean containsSpecialChar(String password) {
        String escapedSpecialChars = Pattern.quote(allowedSpecialChars);
        return Pattern.compile("[" + escapedSpecialChars + "]").matcher(password).find();
    }

    /**
     * 检查是否为常见弱密码
     */
    private boolean isCommonPassword(String password) {
        return COMMON_PASSWORDS.contains(password.toLowerCase());
    }

    /**
     * 检查是否包含连续字符
     */
    private boolean hasSequentialChars(String password) {
        for (int i = 0; i < password.length() - 2; i++) {
            char c1 = password.charAt(i);
            char c2 = password.charAt(i + 1);
            char c3 = password.charAt(i + 2);
            
            // 检查连续递增或递减
            if ((c2 == c1 + 1 && c3 == c2 + 1) || (c2 == c1 - 1 && c3 == c2 - 1)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查是否有过多重复字符
     */
    private boolean hasExcessiveRepeatingChars(String password) {
        int count = 1;
        for (int i = 1; i < password.length(); i++) {
            if (password.charAt(i) == password.charAt(i - 1)) {
                count++;
                if (count > maxRepeatingChars) {
                    return true;
                }
            } else {
                count = 1;
            }
        }
        return false;
    }
}